package net.oschina.arvin.sqlbuilder;

import net.oschina.arvin.sqlbuilder.definition.ColumnDefinition;
import net.oschina.arvin.sqlbuilder.definition.ModelDefinition;
import net.oschina.arvin.sqlbuilder.definition.QueryConditionDefinition;
import net.oschina.arvin.sqlbuilder.utils.AssertUtil;
import net.oschina.arvin.sqlbuilder.utils.Util;

import java.util.*;

/**
 * Sql 构建器上下文， 全局配置
 *
 * @author Arvin
 * @time 2017/11/15 23:19
 */
public class ModelDefinitionContext {

    /** 模型定义 */
    private static final Map<Class<?>, ModelDefinition> modelDefinitionMap = new HashMap<Class<?>, ModelDefinition>();
    /** 查询条件类型 */
    private static final Map<Class<?>, QueryConditionDefinition> queryConditionDefinitionMap = new HashMap<Class<?>, QueryConditionDefinition>();

    /**
     * 注册模型类型，字段，表名，等等
     *
     * @param modelType 模型类型
     */
    public static ModelDefinition registerModelType(Class<?> modelType) {
        if (null != modelType) {
            ModelDefinition modelDefinition = modelDefinitionMap.get(modelType);
            if (null == modelDefinition) {

                modelDefinition = new ModelDefinition(modelType);

                modelDefinitionMap.put(modelType, modelDefinition);

            }
            return modelDefinition;
        }
        return null;
    }

    /**
     * 注册查询条件类型，字段，表名，等等
     *
     * @param queryConditionType 模型类型
     */
    public static QueryConditionDefinition registerQueryConditionType(Class<?> queryConditionType) {
        if (null != queryConditionType) {
            QueryConditionDefinition queryConditionDefinition = queryConditionDefinitionMap.get(queryConditionType);
            if (null == queryConditionDefinition) {

                queryConditionDefinition = new QueryConditionDefinition(queryConditionType);

                queryConditionDefinitionMap.put(queryConditionType, queryConditionDefinition);

            }
            return queryConditionDefinition;
        }
        return null;
    }

    /**
     * 检查指定的属性是否是要进行忽略的
     *
     * @param modelType       模型类型
     * @param modelModelField 模型的java属性名称
     * @return
     */
    public static boolean isIgnoreModelField(Class<?> modelType, String modelModelField) {
        if (null == modelType || Util.isBlank(modelModelField)) {
            return true;
        }
        registerModelTypeIfNotRegister(modelType);

        return false;
    }

    /**
     * 如果没有注册过的话就进行注册
     *
     * @param modelType 模型类型
     */
    private static ModelDefinition registerModelTypeIfNotRegister(Class<?> modelType) {
        ModelDefinition modelDefinition = modelDefinitionMap.get(modelType);
        if (null == modelDefinition) {
            return registerModelType(modelType);
        }
        AssertUtil.assertNotNull(modelDefinition, "无法解析模型定义： " + modelType.getSimpleName());
        return modelDefinition;
    }

    /**
     * 如果没有注册过的话就进行注册
     *
     * @param queryConditionType 查询条件类型
     */
    private static QueryConditionDefinition registerQueryConditionTypeIfNotRegister(Class<?> queryConditionType) {
        QueryConditionDefinition queryConditionDefinition = queryConditionDefinitionMap.get(queryConditionType);
        if (null == queryConditionDefinition) {
            return registerQueryConditionType(queryConditionType);
        }
        AssertUtil.assertNotNull(queryConditionDefinition, "无法解析查询条件定义： " + queryConditionType.getSimpleName());
        return queryConditionDefinition;
    }

    /**
     * 根据模型类型和java属性名称获取数据库列名称
     *
     * @param modelType      模型类型, 注意不是 Query 对象模型
     * @param modelFieldName java属性名称
     * @return
     */
    public static String getWrapColumnNameByModelModelFieldName(Class<?> modelType, String modelFieldName) {
        AssertUtil.assertNotBlank(modelFieldName, "要获取的Java属性名称未提供！");

        ModelDefinition modelDefinition = getModelDefinition(modelType);

        AssertUtil.assertNotNull(modelDefinition, "获取模型对象定义出错！");

        return modelDefinition.getWrapColumnNameByModelFieldName(modelFieldName);
    }

    /**
     * 获取模型定义
     *
     * @param modelType 模型类型
     * @return 返回一个模型定义
     */
    public static ModelDefinition getModelDefinition(Class<?> modelType) {
        AssertUtil.assertNotNull(modelType, "要获取模型定义的类不能为NULL");
        return registerModelTypeIfNotRegister(modelType);
    }

    /**
     * 获取查询条件定义
     *
     * @param queryConditionType 查询条件类型
     * @return 返回一个查询条件定义
     */
    public static QueryConditionDefinition getQueryConditionDefinition(Class<?> queryConditionType) {
        Util.checkQueryConditionType(queryConditionType);

        return registerQueryConditionTypeIfNotRegister(queryConditionType);
    }

    /**
     * 获取主键列定义， 查找 @PrimaryKey 标签修饰的字段
     *
     * @param modelType 模型类型
     * @return 如果没有就返回一个空的列表
     */
    public static List<ColumnDefinition> getPrimaryKeyColumnDefinitions(Class<?> modelType) {
        ModelDefinition modelDefinition = getModelDefinition(modelType);
        if (null != modelDefinition) {
            return modelDefinition.getPrimaryKeyDefinitionList();
        }
        return new ArrayList<ColumnDefinition>();
    }

    /**
     * 根据用户传入的主键属性名称获取主键列定义，如果没有设置要搜索的属性名称将 查找 @PrimaryKey 标签修饰的字段
     *
     * @param modelType       模型类型
     * @param modelFieldNames 自定义的主键模型名称
     * @return 如果没有就返回一个空的列表
     */
    public static List<ColumnDefinition> getPrimaryKeyColumnDefinitionsByCustomModelFieldNames(Class<?> modelType, String... modelFieldNames) {
        if (null == modelFieldNames || modelFieldNames.length < 1) {
            return getPrimaryKeyColumnDefinitions(modelType);
        }
        return getColumnDefinitionsByModelFieldNames(modelType, modelFieldNames);
    }

    /**
     * 获取指定模型名称的列定义
     *
     * @param modelType      模型类型
     * @param modelFieldName 模型名称
     * @return 如果不存在则抛出异常
     * @throws net.oschina.arvin.sqlbuilder.exceptions.SqlBuilderException 如果不存在将抛出这个异常
     */
    public static ColumnDefinition getColumnDefinitionByModelFieldName(Class<?> modelType, String modelFieldName) {
        return getModelDefinition(modelType).getColumnDefinitionByModelFieldName(modelFieldName);
    }

    /**
     * 获取指定模型名称列表的列定义列表
     *
     * @param modelType       模型类型
     * @param modelFieldNames 模型名称列表
     */
    public static List<ColumnDefinition> getColumnDefinitionsByModelFieldNames(Class<?> modelType, String... modelFieldNames) {
        return getColumnDefinitionsByModelFieldNames(modelType, Arrays.asList(modelFieldNames));
    }

    /**
     * 获取指定模型名称列表的列定义列表
     *
     * @param modelType       模型类型
     * @param modelFieldNames 模型名称列表
     */
    public static List<ColumnDefinition> getColumnDefinitionsByModelFieldNames(Class<?> modelType, List<String> modelFieldNames) {
        ModelDefinition modelDefinition = getModelDefinition(modelType);
        if (null != modelDefinition) {

            List<ColumnDefinition> columnDefinitionList = new ArrayList<ColumnDefinition>();

            for (String modelFieldName : modelFieldNames) {
                columnDefinitionList.add(modelDefinition.getColumnDefinitionByModelFieldName(modelFieldName));
            }

            return columnDefinitionList;

        }
        return new ArrayList<ColumnDefinition>();
    }
}
